package com.yungu.swift.autoconfig.oss;

import com.aliyun.oss.OSSClient;
import com.yungu.swift.oss.OSSTemplate;
import com.yungu.swift.oss.annotation.OSSEntrance;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;

/**
 * @Author: cuixiuyin
 * @Date: 2018/11/05
 */

@Slf4j
public class OSSPostProcessor implements BeanPostProcessor {

    private OSSClient client;

    public OSSPostProcessor(OSSClient client) {
        this.client = client;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Object target = getTargetBean(bean);
        Class<?> clazz = AopUtils.getTargetClass(bean);

        for (Field field : clazz.getDeclaredFields()) {
            OSSEntrance annotation = AnnotationUtils.getAnnotation(field, OSSEntrance.class);
            if (annotation != null) {
                OSSTemplate template = new OSSTemplate();
                template.setClient(client);
                template.setBucketName(annotation.bucketName());

                ReflectionUtils.makeAccessible(field);
                ReflectionUtils.setField(field, target, template);
                log.info("[OSSPostProcessor]Create OSSTemplate Success, Set Field: {}.{}", clazz.getCanonicalName(), field.getName());
            }
        }
        return bean;
    }

    @SneakyThrows
    private Object getTargetBean(Object bean) {
        Object target = bean;
        while (AopUtils.isAopProxy(target)) {
            target = ((Advised) target).getTargetSource().getTarget();
        }
        return target;
    }
}
